<template>
	<view class="draggable-list" :style="listStyle">
		<view v-for="(item, index) in localList" :key="item.id" class="draggable-item" :style="getItemStyle(index)">

			<!-- <view @touchstart.stop="touchStart($event, index)"
            @touchmove.stop="touchMove"
            @touchend.stop="touchEnd">
		<slot name="item" :item="item" :index="index"></slot>
	</view> -->
			<view @mousedown.stop="touchStart($event, index)" @mousemove.stop="touchMove" @mouseup.stop="touchEnd">
				<slot name="item" :item="item" :index="index"></slot>
			</view>
		</view>
	</view>
</template>

<script>
	export default {
		name: 'DraggableList',
		props: {
			list: {
				type: Array,
				required: true
			}
		},
		data() {
			return {
				localList: [],
				dragIndex: -1,
				startY: 0,
				currentY: 0,
				isDragging: false,
				itemHeight: 0,
				listHeight: 0,
				moveList: [],
				listTop: 0,
				lastToIndex: -1,
				lastMovingDirection: null
			}
		},
		computed: {
			listStyle() {
				return {
					height: `${this.listHeight}px`
				}
			}
		},
		watch: {
			list: {
				immediate: true,
				deep: true,
				handler(newVal) {
					this.localList = JSON.parse(JSON.stringify(newVal))
					this.$nextTick(() => {
						this.initMoveList()
					})
				}
			}
		},
		mounted() {
			this.$nextTick(() => {
				this.initMeasurements()
			})
		},
		methods: {
			initMoveList() {
				this.moveList = this.localList.map((_, index) => ({
					y: index * this.itemHeight,
					moving: false
				}))
				this.listHeight = this.itemHeight * this.localList.length
			},

			initMeasurements() {
				const query = uni.createSelectorQuery().in(this)
				query.select('.draggable-list').boundingClientRect(data => {
					if (data) {
						this.listTop = data.top
					}
				}).exec()

				query.select('.draggable-item').boundingClientRect(data => {
					if (data) {
						this.itemHeight = data.height
						this.initMoveList()
					}
				}).exec()
			},

			touchStart(e, index) {
				this.isDragging = true
				this.dragIndex = index
				this.startY = e.touches[0].clientY - this.moveList[index].y
				this.currentY = this.moveList[index].y
				this.moveList[index].moving = true
			},

			touchMove(e) {
				if (!this.isDragging) return

				const touchY = e.touches[0].clientY - this.listTop

				// 保存上一次的位置用于判断方向
				const previousY = this.currentY

				// 限制拖动范围在列表内
				this.currentY = Math.max(0, Math.min(touchY - this.startY + this.listTop, this.listHeight - this
					.itemHeight))

				const rawTargetIndex = this.currentY / this.itemHeight
				const targetIndex = Math.round(rawTargetIndex)

				if (targetIndex >= 0 &&
					targetIndex < this.localList.length &&
					targetIndex !== this.dragIndex &&
					Math.abs(rawTargetIndex - targetIndex) < 0.3) {

					// 检测拖动方向变化
					const movingDirection = this.currentY - previousY > 0 ? 'down' : 'up'

					// 移除方向改变时重置所有元素状态的逻辑
					this.lastMovingDirection = movingDirection

					this.updateItemsPosition(this.dragIndex, targetIndex)
				}
			},

			touchEnd() {
				if (!this.isDragging) return

				const rawTargetIndex = this.currentY / this.itemHeight
				const floorIndex = Math.floor(rawTargetIndex)
				const offsetPercentage = rawTargetIndex - floorIndex

				let finalIndex
				if (offsetPercentage > 0.5) {
					finalIndex = floorIndex + 1
				} else {
					finalIndex = floorIndex
				}

				finalIndex = Math.max(0, Math.min(finalIndex, this.localList.length - 1))

				if (finalIndex !== this.dragIndex) {
					const item = this.localList.splice(this.dragIndex, 1)[0]
					this.localList.splice(finalIndex, 0, item)
					this.$emit('update', [...this.localList])
				}

				// 完全重置所有元素的状态
				this.moveList = this.localList.map((_, index) => ({
					y: index * this.itemHeight,
					moving: false,
					animating: false // 确保动画状态也被重置
				}))

				// 重置所有状态变量
				this.isDragging = false
				this.dragIndex = -1
				this.currentY = 0
				this.lastToIndex = -1
				this.lastMovingDirection = null
				this.startY = 0 // 重置起始位置

				// 使用 nextTick 确保视图更新后重新初始化
				this.$nextTick(() => {
					// 重新初始化移动列表
					this.initMoveList()
				})
			},

			updateItemsPosition(fromIndex, toIndex) {
				if (this.lastToIndex === toIndex) return

				const previousToIndex = this.lastToIndex
				this.lastToIndex = toIndex

				const positions = this.moveList.map((item, index) => {
					// 被拖动的元素
					if (index === fromIndex) {
						return {
							...item,
							y: this.currentY,
							moving: true,
							animating: false
						}
					}

					let newY = index * this.itemHeight
					let shouldAnimate = false

					// 确定哪些元素需要移动
					if (fromIndex < toIndex) {
						if (index > fromIndex && index <= toIndex) {
							newY = (index - 1) * this.itemHeight
							shouldAnimate = true
						}
					} else if (fromIndex > toIndex) {
						if (index >= toIndex && index < fromIndex) {
							newY = (index + 1) * this.itemHeight
							shouldAnimate = true
						}
					}

					// 保持现有的动画状态，只在位置真正改变时更新
					const currentPosition = this.moveList[index]
					const positionChanged = currentPosition.y !== newY

					return {
						...item,
						y: newY,
						moving: false,
						animating: positionChanged
					}
				})

				this.moveList = positions
			},

			getItemStyle(index) {
				const moveData = this.moveList[index]
				const isDraggingItem = index === this.dragIndex

				return {
					transform: `translateY(${isDraggingItem ? this.currentY : moveData?.y}px)`,
					transition: moveData?.moving ? 'none' : 'transform 0.3s ease',
					zIndex: isDraggingItem ? 2 : 1,
					boxShadow: isDraggingItem ? '0 2px 10px rgba(0,0,0,0.1)' : 'none',
					pointerEvents: 'auto' // 确保所有元素都可以接收事件
				}
			}
		}
	}
</script>

<style scoped>
	.draggable-list {
		width: 100%;
		position: relative;
		padding: 30rpx 0;
		box-sizing: border-box;
	}

	.draggable-item {
		/* padding: 0rpx 20rpx 20rpx; */
		position: absolute;
		width: 100%;
		left: 0;
		box-sizing: border-box;
		will-change: transform;
	}

	.item-content {
		display: flex;
		align-items: center;
		justify-content: space-between;
	}

	.item-main {
		display: flex;
		align-items: center;
		flex: 1;
	}

	.item-icon {
		width: 40rpx;
		height: 40rpx;
		margin-right: 20rpx;
	}

	.item-text {
		font-size: 28rpx;
	}

	.drag-handle {
		padding: 0 20rpx;
		cursor: move;
	}

	.drag-icon {
		font-size: 48rpx;
		color: #999;
	}
</style>